﻿namespace Arms.Application.Modules.Products
{
    using Arms.Application.Modules.Products.DTOs;
    using Arms.Application.Services;
    using Arms.Domain;
    using Arms.Domain.Modules.Orders;
    using Arms.Domain.Modules.Products;
    using Arms.Framework;
    using System;
    using System.Collections.Generic;
    using System.Linq;

    /// <summary>
    /// Query service regarding the product domain
    /// </summary>
    public class ProductQueryService : ServiceBase, IProductQueryService
    {
        public ProductQueryService(IUnitOfWork uow) : base(uow) { }

        /// <summary>
        /// Returns a list of menu categories by menu id
        /// </summary>
        /// <param name="menuID"></param>
        /// <returns></returns>
        public IEnumerable<EntityDescribedDTO> GetMenuCategories(int menuID)
        {
            var menuCategories = base.UnitOfWork.Repository<MenuCategory>().Get(x => x.MenuID == menuID);
            return menuCategories.Select(x => new EntityDescribedDTO()
            {
                ID = x.ID,
                Name = x.Name,
                Description = x.Description,
                Comment = x.Comment
            });
        }
        /// <summary>
        /// Return a list of all products.
        /// </summary>
        /// <returns></returns>
        public IEnumerable<ProductDTO> GetAllProducts()
        {
            return base.UnitOfWork.Repository<Product>().GetAll().Select(x => new ProductDTO()
            {
                ProductID = x.ID,
                ProductClassID = x.ProductClassID,
                ProductSubClassID = x.ProductSubClassID.ToInt(),
                ProductName = x.Name,
                ProductDescription = x.Description,
                ProductComment = x.Comment,
                Price = x.Price,
            });
        }
        /// <summary>
        /// Returns a list of product classes by menu category id.
        /// </summary>
        /// <param name="menuCategoryID"></param>
        /// <returns></returns>
        public IEnumerable<EntityDescribedDTO> GetProductClassesByMenuCategory(int menuCategoryID)
        {
            List<ProductClass> result = new List<ProductClass>();

            var products = base.UnitOfWork.Repository<MenuCategory>().Query()
                                                                     .SingleOrDefault(x => x.ID == menuCategoryID);

            var productGroups = base.UnitOfWork.Repository<MenuCategory>().Query()
                                                                          .SingleOrDefault(x => x.ID == menuCategoryID);

            if (products != null)
            {
                result.AddRange(products.Products.Select(x => x.ProductClass));
            }

            if (productGroups != null)
            {
                result.AddRange(productGroups.ProductGroups.Select(x => x.ProductClass));
            }

            return result.Distinct(x => x.ID).Select(x => new EntityDescribedDTO()
            {
                ID = x.ID,
                Name = x.Name,
                Description = x.Description,
                Comment = x.Comment
            });
        }
        /// <summary>
        /// Returns a list of products by menu category id.
        /// </summary>
        /// <param name="productClassID"></param>
        /// <returns></returns>
        public IEnumerable<ProductDTO> GetProductsByProductClass(int productClassID)
        {
            List<ProductDTO> result = new List<ProductDTO>();
            var productClass = base.UnitOfWork.Repository<ProductClass>().Find(productClassID);

            if (productClass != null)
            {
                var products = productClass.Products.Select(x => new ProductDTO()
                {
                    ProductID = x.ID,
                    ProductClassID = x.ProductClassID,
                    ProductSubClassID = x.ProductSubClassID.ToInt(),
                    ProductName = x.Name,
                    ProductDescription = x.Description,
                    ProductComment = x.Comment,
                    Price = x.Price,
                });
                var productGroups = productClass.ProductGroups.Select(x => new ProductDTO()
                {
                    ProductGroupID = x.ID,
                    ProductClassID = x.ProductClassID,
                    ProductSubClassID = x.ProductSubClassID.ToInt(),
                    ProductName = x.Name,
                    ProductDescription = x.Description,
                    ProductComment = x.Comment,
                    Price = x.Price,
                });
                result.AddRange(products);
                result.AddRange(productGroups);
            }

            return result;
        }
        /// <summary>
        /// Returns a list of product classes.
        /// </summary>
        /// <returns></returns>
        public IEnumerable<EntityDescribedDTO> GetProductClasses()
        {
            return base.UnitOfWork.Repository<ProductSubClass>().GetAll().Select(x => new EntityDescribedDTO()
            {
                ID = x.ID,
                Name = x.Name,
                Description = x.Description,
                Comment = x.Comment
            });
        }
        /// <summary>
        /// Returns a list of product sub classes.
        /// </summary>
        /// <returns></returns>
        public IEnumerable<EntityDescribedDTO> GetProductSubClasses()
        {
            return base.UnitOfWork.Repository<ProductSubClass>().GetAll().Select(x => new EntityDescribedDTO()
            {
                ID = x.ID,
                Name = x.Name,
                Description = x.Description,
                Comment = x.Comment
            });
        }


        public IEnumerable<ProductDTO> GetProductsInOrder(int orderID)
        {
            List<ProductDTO> result = new List<ProductDTO>();

            var order = base.UnitOfWork.Repository<Order>().Find(orderID);

            if (order != null)
            {
                var products = order.ProductsInOrders.Select(p => p.Product).Select(x => new ProductDTO()
                {
                    ProductID = x.ID,
                    ProductClassID = x.ProductClassID,
                    ProductSubClassID = x.ProductSubClassID.ToInt(),
                    ProductName = x.Name,
                    ProductDescription = x.Description,
                    ProductComment = x.Comment,
                    Price = x.Price,
                });

                result.AddRange(products);
            }

            return result;
        }


        public IEnumerable<ProductsInOrderDTO> GetProductsInOrderWithQuantity(int orderID)
        {
            List<ProductsInOrderDTO> result = new List<ProductsInOrderDTO>();

            var order = base.UnitOfWork.Repository<Order>().Find(orderID);

            if (order != null)
            {
                var productsInOrder = order.ProductsInOrders.Select(x => new ProductsInOrderDTO()
                {
                    OrderID = x.OrderID,
                    ProductID = x.ProductID,
                    ProductName = x.Product.Name,
                    Quantity = x.Quantity
                });
                result.AddRange(productsInOrder);
            }
            return result;
        }
    }
}
